package kaiao.sum;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 三数之和
 *
 * @author kai.ao
 * @since 2024/5/12
 */
public class 三数之和 {

	public static void main(String[] args) {

	}

	public static List<List<Integer>> threeSum(int[] nums) {

		// 初始化返回数组
		List<List<Integer>> ans = new ArrayList<>();

		// 判断当前数组长队小于3直接返回
		int len = nums.length;
		if(len < 3) return ans;

		Arrays.sort(nums); // 排序


		for (int i = 0; i < len ; i++) {

			// 因为是排序过的数组，因此如果当前数字大于0则后续肯定找不到三数和大于0的组合
			if(nums[i] > 0) break;

			// 如果当前占位的数字和前一个数字相同，则跳过，避免重复解
			if(i > 0 && nums[i] == nums[i-1]) continue; // 去重

			// 创建双指针 （指针的概念主要是移动指针在数组中会指向不同值）
			int L = i+1;
			int R = len-1;

			// 单循环中调用前后指针向中间遍历, 因为已排序，所有可以判断双指针的移动方向，如果<0,移动左指针增加数目
			while(L < R){
				int sum = nums[i] + nums[L] + nums[R];
				if(sum == 0){
					ans.add(Arrays.asList(nums[i],nums[L],nums[R]));

					// 原理如上，需要去重
					while (L<R && nums[L] == nums[L+1]) L++; // 去重
					while (L<R && nums[R] == nums[R-1]) R--; // 去重

					// 因为题解不只是一个，因此找到答案后需要移动指针，寻找下一个答案
					L++;
					R--;
				}
				else if (sum < 0) L++;
				else if (sum > 0) R--;
			}
		}
		return ans;
	}


	public List<List<Integer>> copy(int[] nums) {

		// 创建返回数组
		List<List<Integer>> ans = new ArrayList<>();

		// 判断当前数组小于3则直接返回
		if (nums.length < 3) {
			return ans;
		}

		Arrays.sort(nums);
		for (int i = 0; i < nums.length; i++) {

			// 去重
			if (i > 0 && nums[i] == nums[i - 1]) continue;


			// 定义双指针， 左右指针
			int L = i + 1;
			int R = nums.length - 1;

			int sum = 0;
			while (L < R) {

				sum = nums[i] + nums[L] + nums[R];
				if (sum == 0) {
					ans.add(Arrays.asList(nums[i], nums[L], nums[R]));
					// 去重

					while (L < R && nums[L] == nums[L + 1]) L++;
					while (L < R && nums[R] == nums[R - 1]) R--;
					L++;
					R--;
				}
				else if (sum > 0) R--;
				else if (sum < 0) L++;
			}
		}

		return ans;
	}

}
